#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <errno.h>

#include <openssl/evp.h>

#include "debug.h"

int aes_encrypt(unsigned char *plaintext,int palintext_len,unsigned char *key,unsigned char *iv,unsigned char *ciphertext);
int aes_decrypt(unsigned char *ciphertext,int ciphertext_len,unsigned char *key,unsigned char *iv,unsigned char *plaintext);

//gcc -Wall aes_test.c -o aes_test -lssl -lcrypto

int main(int argc,char *argv[])
{
    int ret = -1;
    unsigned char *key = (unsigned char *)"01234567890123456789012345678901";
    unsigned char *iv = (unsigned char *)"0123456789012345";
    unsigned char *plaintext = (unsigned char *)"hello word..IUHNUIENRBIEBNUIHonviowjojeroigo";
    unsigned char ciphertext[128];
    unsigned char decrypttext[128];
    int ciphertext_len,decrypttext_len;

    ciphertext_len = aes_encrypt(plaintext,strlen((const char *)plaintext),key,iv,ciphertext);
    printf("ciphertext_len:%d\r\n",ciphertext_len);
    printf("ciphertext:\r\n");
    for(int i = 0;i < ciphertext_len;i++)
    {
        if(i && (!(i % 10)))
        {
            printf("\r\n");
        }
        printf("%02x ",ciphertext[i]);
    }
    printf("\r\n");
    decrypttext_len = aes_decrypt(ciphertext,ciphertext_len,key,iv,decrypttext);
    printf("decrypttext_len:%d\r\n",decrypttext_len);
    decrypttext[decrypttext_len] = '\0';
    printf("decrypttext:%s\r\n",decrypttext);

    (void)ret;

    return 0;
}

int aes_encrypt(unsigned char *plaintext,int palintext_len,unsigned char *key,unsigned char *iv,unsigned char *ciphertext)
{
    int ret = -1;
    EVP_CIPHER_CTX ctx;
    int ciphertext_len;
    int tmplen;

    EVP_CIPHER_CTX_init(&ctx);

    ret = EVP_EncryptInit_ex(&ctx,EVP_aes_256_cfb128(),NULL,key,iv);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptInit_ex error..\r\n");
        return ret;
    }

    ret = EVP_EncryptUpdate(&ctx,ciphertext,&ciphertext_len,plaintext,palintext_len);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptUpdate error..\r\n");
        return ret;
    }

    ret = EVP_EncryptFinal_ex(&ctx,ciphertext + ciphertext_len,&tmplen);
    if(ret != 1)
    {
        PRINTF("EVP_EncryptFinal_ex error..\r\n");
        return ret;
    }
    ciphertext_len += tmplen;

    EVP_CIPHER_CTX_cleanup(&ctx);

    ret = ciphertext_len;

    return ciphertext_len;
}

int aes_decrypt(unsigned char *ciphertext,int ciphertext_len,unsigned char *key,unsigned char *iv,unsigned char *plaintext)
{
    int ret = -1;
    EVP_CIPHER_CTX ctx;
    int plaintext_len;
    int tmplen;

    EVP_CIPHER_CTX_init(&ctx);

    ret = EVP_DecryptInit_ex(&ctx,EVP_aes_256_cfb128(),NULL,key,iv);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptInit_ex error..\r\n");
        return ret;
    }

    ret = EVP_DecryptUpdate(&ctx,plaintext,&plaintext_len,ciphertext,ciphertext_len);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptUpdate error..\r\n");
        return ret;
    }

    ret = EVP_DecryptFinal_ex(&ctx,plaintext + plaintext_len,&tmplen);
    if(ret != 1)
    {
        PRINTF("EVP_DecryptFinal_ex error..\r\n");
        return ret;
    }
    plaintext_len += tmplen;

    EVP_CIPHER_CTX_cleanup(&ctx);

    ret = plaintext_len;

    return ret;
}
